#include "mymqtt.h"

#include <stdlib.h>
#include <time.h>
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_sntp.h"
#include "esp_netif_sntp.h"
#include "mqtt_client.h"
#include "HMACSHA256.h"


static const char *TAG = "mymqtt";


void iotda_msg_down_topic_handler(const char *msg){
  /* 请在本函数中编写处理 IoTDA 平台下发消息的逻辑代码 */
  ESP_LOGI("LOG", "这是ESP_LOGI,msg_len = %d", strlen(msg));
  ESP_LOGI("LOG", "msg=%s", msg);
}

/*******************************以下代码无需修改*************************************************************/


static esp_mqtt_client_handle_t client = NULL; // 客户端句柄

/**
 * @brief MQTT 事件处理函数
 *
 * @param handler_args: 用户注册回调函数传入的参数
 * @param base        : 事件基，在此事件中一直是 mqtt_base
 * @param event_id    : 事件ID
 * @param event_data  : 事件数据包
 */
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
  esp_mqtt_event_handle_t event = event_data;
  esp_mqtt_client_handle_t client = event->client;
  int msg_id;
  ESP_LOGD(TAG, "free heap size is %" PRIu32 ", minimum %" PRIu32, esp_get_free_heap_size(), esp_get_minimum_free_heap_size());
  switch ((esp_mqtt_event_id_t)event_id)
  {
  case MQTT_EVENT_CONNECTED: // 连接到服务器事件
    ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
    // msg_id = esp_mqtt_client_publish(client, IOTDA_MSG_UP_TOPIC, "hello", 0, 1, 0);
    // ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);

    msg_id = esp_mqtt_client_subscribe(client, IOTDA_MSG_DOWN_TOPIC, 0);
    ESP_LOGI(TAG, "Subscribe %s successful, msg_id=%d", IOTDA_MSG_DOWN_TOPIC, msg_id);
    break;

  case MQTT_EVENT_DISCONNECTED: // 与服务端断开连接事件
    ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
    break;

  case MQTT_EVENT_SUBSCRIBED: // 订阅成功事件
    ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
    break;

  case MQTT_EVENT_PUBLISHED: // 发布主题事件
    ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
    break;

  case MQTT_EVENT_DATA: // 数据事件
    ESP_LOGI(TAG, "MQTT_EVENT_DATA");
    ESP_LOGI(TAG, "TOPIC=%.*s", event->topic_len, event->topic);
    ESP_LOGI(TAG, "DATA=%.*s", event->data_len, event->data);
    event->data[event->data_len] = 0;
    iotda_msg_down_topic_handler(event->data);
    break;

  case MQTT_EVENT_BEFORE_CONNECT: // 即将连接事件
    ESP_LOGI(TAG, "MQTT_EVENT_BEFORE_CONNECT");
    break;

  case MQTT_EVENT_ERROR: // 错误事件
    ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
    ESP_LOGI(TAG, "MQTT return code is %d", event->error_handle->connect_return_code);
    break;
  default:
    ESP_LOGI(TAG, "MQTT_EVENT_XXX id:[%d]", event->event_id);
    break;
  }
}

// 初始化 MQTT
void iotda_mqtt_init(void)
{
  // 使用 SNTP 同步 UTC 标准时间
  time_t time_now;          // 存放当前时间
  char strftime_buf[11];    // 存放格式化后的时间字符串
  esp_sntp_config_t sntp_cfg = ESP_NETIF_SNTP_DEFAULT_CONFIG("ntp3.aliyun.com"); // 配置 SNTP
  esp_netif_sntp_init(&sntp_cfg);
  if (esp_netif_sntp_sync_wait(pdMS_TO_TICKS(10000)) != ESP_OK) {
    ESP_LOGE(TAG, "Failed to update system time within 10s timeout");
    esp_restart(); // 不可忍错误，重启
  }
  time_now = time(NULL);          // 获取当前时间
  strftime(strftime_buf, sizeof(strftime_buf), "%Y%m%d%H", localtime(&time_now)); // 格式化IotDA规定时间戳
  ESP_LOGI(TAG, "The current UTC time is: %s", strftime_buf);

  // 格式化 iotda 客户端登入 ID
  char iot_clientID[strlen(IOTDA_DEVICEID)+5+10+1];
  sprintf(iot_clientID, "%s_0_1_%.10s", IOTDA_DEVICEID, strftime_buf); // 合并出客户端ID

  // 加密 iotda 客户端登入密码
  char iotda_pswd[32*2+1];
  HMACSHA256_encrypt(iotda_pswd, (uint8_t *)IOTDA_DEVICESRCRET, (uint8_t *)strftime_buf);
  ESP_LOGI(pcTaskGetName(NULL), "iot_clientID: %s\tiotda_pswd: %s", iot_clientID, iotda_pswd);

  // mqtt 模块配置信息
  esp_mqtt_client_config_t mqtt_cfg = {
      .broker.address.uri = "mqtt://" IOTDA_IP,           // 服务器地址
      .credentials.client_id = iot_clientID,              // 客户端 ID
      .credentials.username = IOTDA_DEVICEID,             // 客户端用户名
      .credentials.authentication.password = iotda_pswd,  // 客户端登入密码
      .network = {
        .disable_auto_reconnect = false,            // 是否取消自动重连功能
        .reconnect_timeout_ms = 1000,               // 断线后重连的时间间隔
        // .refresh_connection_after_ms = 1000,        // 刷新连接的时间间隔
      },
  };

  // 初始化 MQTT 客户端
  client = esp_mqtt_client_init(&mqtt_cfg);

  // 为所有MQTT事件注册服务回调函数
  esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL); // 为所有MQTT事件注册服务回调函数

  // 启动 MQTT 客户端
  ESP_LOGI(TAG, "MQTT start!");
  esp_mqtt_client_start(client);
}
